package com.navinfo.opentsp.platform.computing.service;

import com.navinfo.opentsp.platform.computing.anno.RoutingProtocol;
import com.navinfo.opentsp.platform.computing.enums.ProtocolEnum;
import com.navinfo.opentsp.platform.computing.enums.YardEnum;
import com.navinfo.opentsp.platform.computing.util.ClassUtils;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

public abstract class AbstractProtocolSerializer {

    protected Map<String, IProtocolParseService> protocolParseServiceMap;
    protected AbstractProtocolSerializer(){

        protocolParseServiceMap = new HashMap<>();
        scanServiceInstance();
    }

    protected IProtocolParseService getServiceInstance(String yardName, String protocol){
        int protocolType = ProtocolEnum.valueOf(protocol).getProtoType();
        IProtocolParseService service = protocolParseServiceMap.get(yardName + protocolType);
        if(service == null){
            service = protocolParseServiceMap.get(YardEnum.COMMON.getYardName() + protocolType);
        }
        return service;
    }

    public void scanServiceInstance(){
        List<Class<?>> list = ClassUtils.getClasses("com.navinfo.opentsp.platform.computing.service");
        for(Class<?> clazz : list){
            if(IProtocolParseService.class.isAssignableFrom(clazz) && IProtocolParseService.class != clazz){
                final RoutingProtocol routingProtocol = clazz.getAnnotation(RoutingProtocol.class);
                if(routingProtocol != null){
                    protocolParseServiceMap.put(routingProtocol.yard().getYardName() + routingProtocol.protocolType().getProtoType(), getInstance(clazz));
                }else if(!Modifier.isAbstract(clazz.getModifiers())){//ignore AbstractClass
                    //abstract class ignore
                }
            }
        }
    }

    public <T> T getInstance(Class<?> clazz){
        try {
            Constructor<?> c = clazz.getDeclaredConstructor();
            if (!c.isAccessible()) {
                c.setAccessible(true);
            }
            return (T)c.newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

//    public void scanServiceInstance(){
//        Reflections reflections = new Reflections(new ConfigurationBuilder()
//                .addUrls(ClasspathHelper.forPackage("com.navinfo.opentsp.platform.computing.service"))
//                .setScanners(new SubTypesScanner(), new TypeAnnotationsScanner().filterResultsBy(new FilterBuilder().include(IProtocolParseService.class.getName())))
//        );
//        Set<Class<? extends IProtocolParseService>> messageClazzSet =  reflections.getSubTypesOf(IProtocolParseService.class);
//        for (Class<? extends IProtocolParseService> messsageClazz : messageClazzSet) {
//            final RoutingProtocol routingProtocol = messsageClazz.getAnnotation(RoutingProtocol.class);
//            if(routingProtocol != null){
//                protocolParseServiceMap.put(routingProtocol.yard() + routingProtocol.protocolType(), getInstance(messsageClazz));
//            }else if(!Modifier.isAbstract(messsageClazz.getModifiers())){//ignore AbstractClass
//                //abstract class ignore
//            }
//        }
//    }
    public static void main(String[] args) {
        Properties prop = new Properties();
        try {
            prop.load(AbstractProtocolSerializer.class.getClass().getResourceAsStream("/config.properties"));
            System.out.println(prop);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
